/*   This file is part of Super Luigi Bros.
 *
 *   Super Luigi Bros is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Super Luigi Bros is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Super Luigi Bros.  If not, see <http://www.gnu.org/licenses/>.
 */
package luigibros.data.zip;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipException;

import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import luigibros.data.ImageStore;
import luigibros.data.xml.level.ImageMap;
import luigibros.data.xml.level.Level;
import luigibros.data.xml.level.Manifest;
import luigibros.logic.Game;
import luigibros.logic.ScreenOccupant;
import luigibros.util.LazyList;

public class LevelZip {
	private static LevelZip defaultImages;
	
	public static void setDefaultImageContainer(String file, Unmarshaller xmlReader) throws ZipException, IOException, JAXBException {
		defaultImages = new LevelZip(new File(file), xmlReader);
	}
	public static void setDefaultImageContainer(File file, Unmarshaller xmlReader) throws ZipException, IOException, JAXBException {
		defaultImages = new LevelZip(file, xmlReader);
	}
	public static void setDefaultImageContainer(InputStream file, Unmarshaller xmlReader) throws ZipException, IOException, JAXBException {
		defaultImages = new LevelZip(file, xmlReader);		
	}
	
	private Unmarshaller xmlReader;
	private ZipFileReader archive;
	private Level level;
	private Manifest manifest;
	private LevelZip[] parents;
	
	public LevelZip(File file, Unmarshaller xmlReader) throws ZipException, IOException, JAXBException {
		this.xmlReader = xmlReader;
		loadFromZip(new ZipFileReader(file));
	}
	public LevelZip(InputStream file, Unmarshaller xmlReader) throws ZipException, IOException, JAXBException {
		this.xmlReader = xmlReader;
		File temp = File.createTempFile("luigi_temp_zip_level_"+UUID.randomUUID(), ".zip.tmp");
		FileOutputStream out = new FileOutputStream(temp);
		int next = 0;
		while((next = file.read()) != -1)
			out.write(next);
		loadFromZip(new ZipFileReader(temp));
		
	}
	private void loadFromZip(ZipFileReader file) throws JAXBException, IOException {
		archive = file;
		manifest = (Manifest)xmlReader.unmarshal(archive.getEntryStream("manifest.xml"));
		parents = new LevelZip[manifest.importedZips.length];
		for(int x = 0; x < manifest.importedZips.length; ++x)
			if(manifest.importedZips[x].internal)
				parents[x] = new LevelZip(archive.getEntryStream(manifest.importedZips[x].path), xmlReader);
			else
				parents[x] = new LevelZip(new File(manifest.importedZips[x].path), xmlReader);
		if(manifest.levelStore != null)
			level = (Level)xmlReader.unmarshal(archive.getEntryStream(manifest.levelStore));
	}
	
	public ImageMap getImageMap() throws JAXBException, IOException {
		if(manifest.imagesStore != null)
			return (ImageMap)xmlReader.unmarshal(archive.getEntryStream(manifest.imagesStore));
		else return null;
	}
	
	public Game getGame() {
		List<ScreenOccupant> occupants = new LazyList<ScreenOccupant>(level.occupants.length);
		for(Level.OccupentRecord record : level.occupants) {
			try {
				ScreenOccupant occ = (ScreenOccupant)(Class.forName(record.getClassName()).newInstance());
				occ.setX(record.getPosX());
				occ.setY(record.getPosY());
				occ.parseCreationString(record.getCreationString());
				occupants.add(occ);
			} catch(Exception e) {
				System.err.println(e.getMessage());
				System.exit(1);
			}
		}
		return new Game(occupants);
	}
	
	public LevelZip[] getParents() {return parents;}
	
	public ZipFileReader getArchive() {return archive;}
	
	public ImageStore getImageStore() throws JAXBException, IOException {
		ZipImageStore store = new ZipImageStore(defaultImages.getImageMap(), defaultImages.getArchive());
		for(LevelZip p : parents)
			store.addSource(p.getImageMap(), p.getArchive());
		store.addSource(getImageMap(), getArchive());
		return store;
	}
}
